//
// Created by chizuru on 2025/10/24.
//

#include "CameraApp.h"
#include "TinyXmlRegisterCLBMap.h"
#include "PxdSerialAdapter.h"
#include "DeviceComm.h"
#include "CameraDevice.h"
#include "BOBCATCameraService.h"
#include "ConnectivityMonitor.h"
#include <windows.h>
#include "xcliball.h"
#include "ProtocolCodecFactory.h"
#include "ReconnectDecorator.h"
#include "LoggingDecorator.h"
#include "test-live-demo.h"
#include <thread>
#include <iostream>
using namespace std;

AUTO_REGISTER_FACTORY(xclib_client::CameraApp, "lazy", [](){ try { return std::make_shared<xclib_client::CameraApp>(); } catch (std::exception e) { std::cerr << "Error: " << e.what() << std::endl;} });
xclib_client::CameraApp::CameraApp() {
    int r = pxd_PIXCIopen(/*"-IM 327680000 -MB 65536 -CQ 512 -BS 1 -DM 15 -PO 5000 -XU 1 -XM 1 -MU 106 -QU 1 -QS 1 -TI 1 -SB 1024"*/
            "",
            "",
            "es.fmt"); // 根据设备初始化参数配置
    if (r < 0) {
        std::cerr << pxd_mesgErrorCode(r) << std::endl;
        exit(-1);
    }

    r = pxd_infoUnits();
    if (r <= 0) {
        throw std::exception(pxd_mesgErrorCode(r));
    }

    try {
        reg_map = std::make_shared<TinyXmlRegisterCLBMap>("bobcat_regs_generated.xml");
    } catch (std::exception e) {
        std::cerr << "Error: " << e.what() << std::endl;
        exit(-1);
    }

    for (int s = 0; s < r; s++) {
        auto entry = std::make_shared<EntryCamera>();
        entry->unit = 1 << s;
        entry->adapter = std::make_shared<PxdSerialAdapter>(entry->unit);
        entry->logging_wapper_adapter = std::make_shared<LoggingDecorator>(entry->adapter);
        entry->device_comm = std::make_shared<DeviceComm>(*entry->adapter);
        entry->device_comm->configureSerial(115200, 8, 0, 1, 0);
        entry->camera_device = std::make_shared<CameraDevice>(*entry->device_comm, ProtocolCodecFactory::instance().create("camera_link_default"));
        entry->camera_service = std::make_shared<BOBCATCameraService>(*entry->camera_device, reg_map);
        entry_cameras.push_back(entry);
        entry_map[entry->unit] = entry;

    }

}

xclib_client::CameraApp::~CameraApp() {
    int r = pxd_PIXCIclose();
    if (r < 0) {
        throw std::exception(pxd_mesgErrorCode(r));
    }
}

void xclib_client::CameraApp::ping(uint16_t unit) {
    auto it = entry_map.find(unit);
    if (it != entry_map.end()) {
        auto e = it->second.lock(); // 将 weak_ptr 转换为 shared_ptr
        if (e) {
            auto ok = e->camera_service->checkIfCameraConnected();
            if (ok.success) {
                std::cout << "Camera connected.\n";
            } else {
                std::cout << "Camera not connected.\n";
            }
        } else {
            throw std::runtime_error("Camera entry has expired.");
        }
    } else {
        throw std::invalid_argument("Invalid unit.");
    }
}

void xclib_client::CameraApp::ls(uint16_t unit) {
    std::cerr << "Video Field Count = " << pxd_videoFieldCount(unit) << std::endl; // 视频源连接到图像采集卡，计数递增
}

void xclib_client::CameraApp::get(uint16_t unit, const string &register_name) {
    auto it = entry_map.find(unit);
    if (it != entry_map.end()) {
        auto e = it->second.lock(); // 将 weak_ptr 转换为 shared_ptr
        if (e) {
            auto ok = e->camera_service->getRegisterCommand(register_name);
            if (!ok.success){
                std::cout << ok.message << std::endl;
            }
        } else {
            throw std::runtime_error("Camera entry has expired.");
        }
    } else {
        throw std::invalid_argument("Invalid unit.");
    }
}

void xclib_client::CameraApp::set(uint16_t unit, const string &register_name, uint32_t val) {
    auto it = entry_map.find(unit);
    if (it != entry_map.end()) {
        auto e = it->second.lock();
        if (e) {
            auto ok = e->camera_service->setRegisterCommand(register_name,  val);
            if (!ok.success){
                std::cout << ok.message << std::endl;
            }
        } else {
            throw std::runtime_error("Camera entry has expired.");
        }
    }

}

void xclib_client::CameraApp::live(uint16_t unit) {
    auto it = entry_map.find(unit);
    if (it != entry_map.end()) {
        auto e = it->second.lock();
        if (e) {
            e->live_thread = std::jthread(liveThread, unit, std::format("Camera_{}", unit));
        } else {
            throw std::runtime_error("Camera entry has expired.");
        }
    } else {
        throw std::invalid_argument("Invalid unit.");
    }
}

void xclib_client::CameraApp::unlive(uint16_t unit) {
    auto it = entry_map.find(unit);
    if (it != entry_map.end()) {
        auto e = it->second.lock();
        if (e) {
            e->live_thread.request_stop();
        } else {
            throw std::runtime_error("Camera entry has expired.");
        }
    }
}
